Математическая среда Matlab. Примеры
решения задач
Символы и текстовые строки в MATLAB вводятся при помощи простых кавычек. Во внутреннем представлении символы даны целыми числами. Конвертировать массив символов в числовую матрицу позволяет команда double. Обратная операция совершается по команде char. Печатаемые символы из стандартного набора ASCII представлены числами от 32 до 255. Объединить текстовые строки можно, просто заключив их в квадратные скобки или при помощи команды strcat. Приведем примеры для данных команд. Вначале введем строку:
>> s = 'Привет'
s =
Привет
Отметим, что для ввода русских букв следует выбрать в меню File/ Preferences/ Command Windows Font шрифт с русской кодировкой. Теперь найдём коды введённых символов:
>> v = double(s)
v =
207 240 232 226 229 242
Объединим две строки:
>> h = [v + ' от MATLAB']
v =
Привет от MATLAB
Тот же результат получится, если вместо переменной v использовать строковую переменную s. В завершение попробуем применить команду strcat. Для перевода численных данных в строковые переменные имеется ряд команд преобразования. В табл. 1. приведены некоторые команды для этих и обратных операций, а полных список можно получить по команде help strfun.
Таблица 1. Логические операции.
|
Имя команды |
Действие |
|
num2str |
Перевод числа в строку |
|
int2str |
Перевод целого числа в строку |
|
mat2str |
Преобразование матрицы в строку |
|
str2mat |
Объединение строк в матрицу |
|
str2num |
Преобразование строки в число |
|
strcat |
Объединение строк |
Приведём пример:
>>
z=1.2e3; strcat('z=',num2str(z))
ans =
z=1200
Массивы с числом размерностей более двух считаются многомерными. Такие массивы могут быть считаны из файла или созданы при помощи команд, таких как zeros, ones, rand. Число параметров при обращении к этим командам должно соответствовать размерности вводимого массива. Например, трёхмерный массив 2х4х2 из нулей будет организован по команде
>> S=zeros(2,4,2)
S(:,:,1) =
0 0 0 0
0 0 0 0
S(:,:,2) =
0 0 0 0
0 0 0 0
Обращение к элементам многомерного массива производятся по обычным правилам работы с массивами, так что действуют двоеточия для указания диапазона, а end обозначает максимальное значение данной размерности. Чтобы изменить какой-нибудь элемент, достаточно присвоить ему значение точно так же, как для обычных массивов, а если элемента не было, то произойдёт увеличение размерности массива:
>> S(3,1,2)=13; size(S(:,:,1))
ans =
3 4
Заметим, что пополнение массива означает дополнительные затраты времени на переписывание данных. Поэтому для повышения скорости расчёта рекомендуется описывать максимальную размерность массива сразу (резервировать память), если это возможно. Когда многомерный массив организуется для хранения нескольких матриц одинакового размера, то первые два индекса удобнее отвести под строки и столбцы матриц, а последний индекс – для номера матрицы. Тогда в результате получим:
>> S2=S(:,:,end)
S2 =
0 0 0 0
0 0 0 0
13 0 0 0
Напомнить, что резервирование памяти ускоряет работу в среде MATLAB, поскольку не расходуется время на пополнение массивов.
Для хранения разнородных объектов (массивов
разных размерностей, разнотипных данных) удобно пользоваться массивами ячеек,
которые создаются двумя способами: по команде cell
или заключением объектов в круглые скобки. Например:
>>
C={sum(S) min(max(S)) sum(sum(sum(S)))}
C =
[1x4x2 double] [1x1x2 double] [13]
Для указания элементов массива используются фигурные скобки, так что в результате обращения к третьему элементу массива C получим число 13:
>> C{3}
ans =
13
а содержимое первого элемента массива ячеек C есть:
>> C1=C{1}
C1(:,:,1) =
0 0 0 0
C1(:,:,2) =
13 0 0 0
Для превращения структуры C1 в обычный массив можно воспользоваться командами squeeze или shiftdim, которые удаляют равные единице размерности (матрица в один столбец или одну строку превращается в вектор):
>>
C2=shiftdim(C1)'
C2 =
0 0 0 0
13 0 0 0
Нужно помнить, что составные части массива ячеек представлены копиями, так что при изменении исходного массива S в объекте C никаких изменений не произойдёт. Иными словами, это не указатель на массив, а сам массив. Для преобразования массива символов в массив ячеек применяется команда cellstr, а обратная процедура реализуется командой char. Если потребуется создать текст из нескольких строк, то обычный приём отделения строк точкой с запятой может не сработать, поскольку все строки должны быть одной длины. В таких случаях можно подготовить массив ячеек:
>> C={'One';'Three';'Seven'}
C =
'One'
'Three'
'Seven'
и затем преобразовать его при помощи команды char:
>>
S=char(C)
S =
One
Three
Seven
Для получения строк одной длины MATLAB добавляет нужное число пробелов, что легко увидеть, затребовав данные о размерностях массива S:
>> size(S)
ans =
3 5
Структурами MATLAB (тип struct) являются многомерные массивы. Доступ к ним осуществляется путём указания индексов-имён. Например, можно создать скалярную структуру из двух полей:
>> S.name='трап'; S.order=2
S =
name: 'трап'
order: 2
Расширение структуры производится по тому же правилу, что и добавление строк и столбцов в массив:
>>
S(2).name='симп'; S(2).order=4;
Для пополнения структуры можно также использовать специальную команду struct. Организуем третий элемент структуры S, присвоив полю name значение «прям», а полю order - значение 2.
>>
S(3)=struct('name','прям','order',2)
S =
1x3 struct array with fields:
name
order
Чтобы вывести содержимое отдельных полей структуры, нужно использовать фигурные либо квадратные скобки в зависимости от того, символьные или числовые данные связаны с данным полем:
>> {S.name}
ans =
'трап' 'симп' 'прям'
>> [S.order]
ans =
2 4 2
Преобразование данных в массив символов осуществляется по команде char:
>> char(S.name)
ans =
трап
симп
прям
Краткий обзор встроенных средств
решения типовых задач алгебры и анализа
Решение систем линейных уравнений
В системе MATLAB для решения систем линейных уравнений предусмотрены знаки
операций - это знаки / и \.
Рассмотрим систему линейных уравнений вида Ay = b,
где А - заданная квадратная матрица N х N, a b - заданный вектор-столбец длины N. Для нахождения неизвестного вектор-столбца у достаточно применить операцию \ и вычислить выражение А\b. Вот соответствующий пример:
А = [1,-2,3,-1;2,3,-4,4;3,1,-2,-2;1,-3,7,6];
b = [б;-7;9;-7];
у = А \ b
У =
2.0000
-1.0000
-2.0000
В общем случае операция \ называется левым делением матриц и, будучи примененная к матрицам А и В в виде А\В, примерно эквивалентна вычислению выражения inv(A)*B
но при этом вычисляется по-другому. Здесь под inv (А) понимается вычисление матрицы, обратной к матрице А.
Операцию / называют правым
делением матриц. Выражение А/В примерно соответствует
вычислению выражения B*inv(A).
Значит, эта операция позволяет решать системы линейных уравнений вида YA = В, так как решением
именно этого уравнения служит выражение B*inv (A).
Нахождение нулей функций(корней
уравнения)
На практике часто приходится сталкиваться с задачей о нахождении корней уравнений. Любое уравнение можно записать в виде равенства некоторой функции нулю, так что это и есть задача о нахождении нулей функций.
Решение указанной задачи осуществляет функция fzero. В качестве первого аргумента ей передается имя функции, задающей исходное уравнение. Вторым аргументом служит начальное приближение к корню:
fzero(name, x0)
Возвращаемым значением функции fzero является нуль функции name в окрестности точки х0.
Для примера рассмотрим задачу о нахождении нулей функции cos(x) на отрезке от 0 до pi. В качестве начального приближения примем х0=1. Вызываем функцию fzero с указанным начальным приближением и получаем следующий результат:
х = fzero('cos',1 )
1.5708
Легко видеть, что мы в качестве нуля функции cos(x) получили значение, близкое к точному значению корня, равному pi/2.
Если требуется найти корень функции, отличной от стандартной (встроенной в систему MATLAB) и тем самым не имеющей в рамках системы MATLAB фиксированного имени, то нужно приписать некоторое имя выражению, вычисляющему функцию.
Пусть, например, требуется найти корни уравнения cos(х) = х, что эквивалентно нахождению нулей функции, вычисляемой по формуле у = cos (х)-х, не имеющей в рамках системы MATLAB фиксированного имени. В этом случае нужно в любом простейшем текстовом редакторе (типа встроенного в операционную систему Windows редактора Notepad) набрать две строки следующего кода:
function у = MyFunctionl( х ) у = cos(x) - х
и запомнить их в файле MyFunctionl .m,
который нужно разместить в текущем каталоге системы MATLAB (узнать его можно
командой cd). После этого можно воспользоваться
функцией fzero:
х = fzero('MyFunctionl',pi/2)
0.7391
Если найдено
абсолютно точное значение корня, то значение функции в этой точке равно нулю.
Таким образом, величина функции в приближенно найденном нуле косвенно
характеризует погрешность результата. Чтобы управлять погрешностью, нужно
осуществлять вызов функции fzero с тремя аргументами:
fzero ( name, x0, tol )
где параметр tol задает требуемую величину погрешности (ошибки). Повторим предыдущие вычисления, потребовав большей точности расчетов (то есть меньшей погрешности):
format long
х = fzero('MyFunctionl',pi/2, le-8)
x =
0.73908513263090
MyFunctionl(x)
ans = 9.778322596076.805e-010
откуда видно, что действительно достигнута большая точность нахождения нуля функции.
Еще раз подчеркнем, что функция fzero находит нули только вещественно-значных функций одной вещественной переменной. Однако часто бывает необходимо найти комплексные корни вещественнозначных функций, особенно в случае многочленов.
Для этой цели в системе MATLAB существует специальная функция roots, которой в качестве аргумента передается массив коэффициентов многочлена. Например, для многочлена х4-ЗхЗ + Зх2- З х + 2, имеющего два вещественных (1 и 2) и два комплексных корня (i и -i), нужно сначала сформировать массив его коэффициентов:
Coef = [ 1, -3, 3, -3, 2 ] после чего вызвать функцию roots:
r = roots(
Coef )
r =
2.00000000000000
0.00000000000000 + 1.00000000000000i
0.00000000000000 - 1.00000000000000i
1.00000000000000
В задаче о нахождении нулей функции сложным моментом является нахождение начального приближения к нулю функции, а также оценка их количества. Поэтому важно параллельно с применением функций типа roots или fzero визуализировать поведение искомых функций на том или ином отрезке значений аргумента. Максимальное содействие в этом может оказать функция fplot (name, [x0, xl]), строящая график функции с именем name на отрезке от х0 до xl.
Например, для ранее рассмотренной функции MyFunctionl с помощью вызова функции
fplot('MyFunctionl',[0,pi/2])-
убеждаемся, что на отрезке от 0 до pi/2 действительно существует единственный нуль этой функции (см. рис. 4.4).
Функция fplot требует от пользователя еще меньше подготовительной работы, чем даже изученная нами ранее функция plot.
Поиск минимума функции
В системе MATLAB имеются специальные функции для поиска минимумов заданных функций. При этом возможен поиск минимума как для функции одной вещественной переменной, так и для функций многих переменных.
Для функций одной переменной их минимумы разыскивает функция fmin:
fmin( name, x0, x1 )
Здесь name представляет имя функции, у которой находятся минимумы, а х0 и xl задают отрезок поиска. Иллюстрировать работу этой функции будем на примере функции hump (переводится как «горб»), специально поставляющейся с системой MATLAB в демонстрационных целях. Эта функция задается формулой
у = 1./((х - 0.3).^2 + 0.01)+1./((х - 0.9).^2 + 0.04) - а ее график легко получается с помощью вызова функции
fplot( 'humps', [0,3] )
Из рисунка видно, что локальный минимум этой функции существует на отрезке от 0.5 до 1.0. Попробуем найти точку минимума следующим вызовом функции fmin:
х = fmin( 'humps', 0.5, 1.0 )
х =
0.63701067459059
|
|
xmin = fmins( name, x0 )
Здесь name является именем функции нескольких переменных, для которой ищется минимум, а х0 - это вектор ее аргументов, с которого начинается поиск. Для иллюстративного примера создадим простую функцию двух переменных
function у = MyFunc2( х ) у = х(1)^2 + х(2)^2;
имеющую минимумом точку (0,0). Этот текст надо записать в файл MyFunc2 .m в текущий каталог системы MATLAB. После этого можно вызвать функцию fmins:
xmin = fmins ( 'MyFunc2', [1,1] ); которая приближенно находит вектор xmin координат точки минимума:
xmin(1)
ans =
-2.102352926236483е-005
xmin(2)
ans =
2.548456493279544е-005
Обе найденные координаты близки к своим точным значениям, равным нулю.
Для функций нескольких переменных еще важнее, чем для ранее рассмотренных функций одной вещественной переменной, постараться априорно оценить количество и приблизительное нахождение локальных минимумов. Тут могут существенно помочь трехмерные графики (plot3d).
Вычисление определенных интегралов
Из всех методов вычисления определенных интегралов самым простым, но в то же время довольно успешно применяемым является метод трапеций.
Для вычисления интегралов методом трапеций в ней предусмотрена функция trapz:
• Integ = trapz( х, у ) ;
Одномерный массив х (вектор) содержит дискретные значения аргументов подынтегральной функции. Значения подынтегральной функции в этих точках сосредоточены в одномерном массиве у. Чаще всего для интегрирования выбирают равномерную сетку, то есть значения элементов массива х отстоят друг от друга на одну и ту же величину- шаг интегрирования. Точность вычисления интеграла зависит от величины шага интегрирования: чем меньше этот шаг, тем больше точность.
Вычислим простой интеграл
b
S cos (x)dx
a
методом трапеций с разной величиной шага интегрирования. Сначала зададим шаг интегрирования равным pi/10:
dx = pi/10;
х = 0:dx:pi; y=cos(x); I = trapz(x,y);
I =
5.5511e-017
и получим поразительно точный результат (абсолютно точный равен нулю), который бесполезно пытаться улучшать, так как уже достигнута предельная точность, обусловленная конечной точностью хранения вещественных чисел на компьютере (примерно 16 десятичных знаков после запятой).
Такая высокая точность является скорее исключением, чем правилом. Обычно же для достижения высокой точности требуется выполнять интегрирование с очень малыми шагами, а контроль достигнутой точности осуществлять путем сравнения последовательных результатов. Например, при вычислении методом трапеций интеграла
5
Ssin (х) * exp(-x)dx о с шагом интегрирования dx = 1
dx = 1; х = 0:dx:5; у = sin(x) .* ехр(-х);
12 = trapz(x,y);
получается следующий результат:
12 = 0.4226
Если провести повторное интегрирование с шагом dx = 0.1, то результат будет
12 = 0.5014
Уменьшая далее шаги интегрирования последовательно в 10 раз, находим, что при dx = 0.01 интеграл равен 0.5023, то есть уже здесь видна тенденция к стабилизации результата. При dx = 0.001 снова получаем
12 = 0.5023
так что в пределах четырех десятичных цифр после запятой результат получен окончательно. Напомним, что если мы хотим наблюдать дальнейшие десятичные цифры, то нужно предварительно ввести и исполнить команду
format long
Метод трапеций является очень универсальным методом и хорошо подходит для интегрирования не слишком гладких функций. Если же функция под знаком интеграла является гладкой (существуют и непрерывны несколько первых производных), то лучше применять методы интегрирования более высоких порядков точности. При одном и том же шаге интегрирования методы более высоких порядков точности достигают более точных результатов.
В системе MATLAB методы интегрирования более высоких порядков точности реализуются функциями quad (метод Симпсона) и quadS (метод Ньютона -Котеса 8-го порядка точности). Оба этих метода являются к тому же адаптивными. Последнее означает, что пользователю нет необходимости контролировать достигнутую точность результата путем сравнения последовательных значений, соответствующих разным шагам интегрирования. Все это указанные адаптивные функции выполняют самостоятельно.
У функции quad8 более высокий порядок точности по сравнению с функцией quad, что очень хорошо для гладких функций, так как обеспечивается более высокая точность результата при большем шаге интегрирования (меньшем объеме вычислений). Однако функция quad может иметь не меньшее, а даже большее быстродействие для не слишком гладких функций (разрывны или велики по абсолютной величине вторая или третья производные). В любом случае обе эти функции по умолчанию обеспечивают одинаковую относительную точность результата, равную 0.001.
Как и многие другие функции системы MATLAB, функции quad и quad8 могут принимать различное количество параметров. Минимальный формат вызова этих функций включает в себя три параметра: имя подынтегральной функции, нижний предел интегрирования и верхний предел интегрирования. Если применяется четвертый параметр, то он является требуемой относительной точностью результата вычислений. Кстати, если обе эти адаптивные функции не могут обеспечить получение необходимой точности (расходящийся или близкий к этому интеграл), то они возвращают символическую бесконечность Inf.
Выше в подразделе «Поиск минимума функции» мы приводили график функции humps, для которой там разыскивались локальные минимумы. Вычислим теперь определенный интеграл от этой функции в пределах от нуля до трех, воспользовавшись для этого обеими адаптивными функциями:
{ I, cnt ] = quad( 'humps', 0,
3 );
23.9681 cnt = 225
[ 18 cnt8 ] = quadS( 'humps', 0, 3 ); 18 =
23.9681 cnt8 =
113
Второе из возвращаемых значений для этих функций означает количество точек, в которых пришлось вычислять подынтегральную функцию. Таким образом, этот параметр характеризует трудоемкость метода. Сравнивая полученные показатели, приходим к выводу, что при интегрировании такой гладкой функции, как humps, преимущество имеет метод quadS, так как для достижения минимальной точности в 0.001 (а по ходу дела может достигаться и более высокая точность) ему требуется меньшее количество вычислений с подынтегральной функцией (113 против 225).
Из высшей математики известно, что к определенным интегралам могут быть сведены многие другие типы интегралов, например криволинейные интегралы. Таким образом, с помощью функций quad, quad8 (или trapz) можно вычислить и эти интегралы.
Рассмотрим пример на криволинейные интегралы первого рода. Пусть требуется вычислить массу М винтовой линии С:
х = sin(t); у
= 2cos(t); z =3t; 0 <= t <= 2;
с постоянной линейной плотностью, равной 5. Задача решается с помощью криволинейного интеграла первого рода:
М = S 5ds,
с
который сводится к вычислению следующего обыкновенного определенного интеграла:
М
= 5j V(*')2 + (У')2 + (z'fdt = 5j Vcos2 t + 4 sin2 t
+ 9dt.
Для вычисления подынтегральной функции создадим следующий текст:
function z = MyFunc321( t )
z = sqrt( cos(t).Л2 + 4*sin(t).A2 t 9 );
который запишем в файл MyFunc321 .m, после чего вызываем функцию quad:
М = 5 * quad( 'MyFunc321', 0, 2 ); М =
34.2903
Двойные интегралы сводятся к вычислению повторных определенных интегралов, один из которых является внутренним, а другой внешним. Внутренний интеграл является подынтегральной функцией для внешнего интеграла. Можно
было бы написать некоторую цепочку вычислений (программу), в которой многократные вычисления подынтегральной функции сводились бы к многократным вызовам функции quad. Однако нет необходимости делать это самостоятельно, так как в системе MATLAB для этого имеется специальная функция dblquad.
В результате в случае необходимости вычисления двойного интеграла, такого, как, например, интеграл
1 2
S S (x sin (у) + у sin (x) )dxdy, о 1 достаточно оформить подынтегральную функцию в следующем виде:
function z = Fof2Var( x, у ) z = x.*sin(y) + y.*sin(x);
(записав этот текст в файл Fof 2Var .m) и вызвать функцию dblquad:
J = dblquad( 'Fof2Var', 0, 1, 1, 2 ); J = 1.1678
в результате чего и получим искомое значение двойного интеграла (это чисто учебный пример, так как данный интеграл аналитическими преобразованиями сводится к произведению однократных определенных интегралов).
xmin3(l) ans =
-1.3474 xmin3(2) ans =
0.2045 Opts(10) ans =
88
Обычно чем дальше от истинного минимума располагается начальная точка для итераций, тем больше требуется их число:
[xmin3,0pts] = fmins( 'MyPeaks', [-2,0] );
xmin3(l)
ans =
-1.3474 xrain3(2) ans =
0.2045 Opts (10) ans =
106
Как только мы задали худшее начальное приближение, так тут же получили возросшее число необходимых итераций для достижения одной и той же точности.